<template>
  <div class="form-renderer">
    <a-form
      :model="model"
      :layout="formLayout"
      :label-align="labelAlign"
      :label-col-props="{ span: labelColSpan }"
      :label-col-style="labelColStyle"
      :wrapper-col-props="wrapperCol"
    >
      <a-row class="draggable_chunk arco-row">
        <a-col
          v-for="item in fields"
          :key="item.field"
          class="column_chunk"
          :span="colSpan(item)"
        >
          <a-form-item :label="item.label" :field="item.field">
            <div class="field-wrap">
              <component
                class="field-control"
                :is="resolveEffectiveComp(item)"
                :key="item.field + ':' + resolveEffectiveComp(item)"
                v-model="model[item.field]"
                v-bind="effectiveProps(item)"
                :options="effectiveOptions(item)"
              />
              <a-dropdown v-if="showVariableTrigger" trigger="click" position="br">
                <a-button type="text" size="mini" class="var-float-btn">
                  <IconThunderbolt />
                </a-button>
                <template #content>
                  <template v-if="varBindings[item.field]">
                    <a-doption @click="clearVariable(item)">清除变量</a-doption>
                  </template>
                  <template v-if="hasGrouped">
                    <a-tabs size="mini">
                      <a-tab-pane key="process" title="流程变量">
                        <template
                          v-if="grouped.process && grouped.process.length"
                        >
                          <a-doption
                            v-for="v in grouped.process"
                            :key="v.value"
                            @click="applyVariable(item.field, v.value)"
                          >
                            {{ v.label || v.value }}
                          </a-doption>
                        </template>
                        <a-doption v-else disabled>暂无流程变量</a-doption>
                      </a-tab-pane>
                      <a-tab-pane key="output" title="出参变量">
                        <template
                          v-if="grouped.output && grouped.output.length"
                        >
                          <a-doption
                            v-for="v in grouped.output"
                            :key="v.value"
                            @click="applyVariable(item.field, v.value)"
                          >
                            {{ v.label || v.value }}
                          </a-doption>
                        </template>
                        <a-doption v-else disabled>暂无出参变量</a-doption>
                      </a-tab-pane>
                      <a-tab-pane key="system" title="系统变量">
                        <template
                          v-if="grouped.system && grouped.system.length"
                        >
                          <a-doption
                            v-for="v in grouped.system"
                            :key="v.value"
                            @click="applyVariable(item.field, v.value)"
                          >
                            {{ v.label || v.value }}
                          </a-doption>
                        </template>
                        <a-doption v-else disabled>暂无系统变量</a-doption>
                      </a-tab-pane>
                    </a-tabs>
                  </template>
                  <template v-else>
                    <template v-if="variablesList.length">
                      <a-doption
                        v-for="v in variablesList"
                        :key="v.value"
                        @click="applyVariable(item.field, v.value)"
                      >
                        {{ v.label || v.value }}
                      </a-doption>
                    </template>
                    <a-doption v-else disabled>暂无可用变量</a-doption>
                  </template>
                </template>
              </a-dropdown>
            </div>
          </a-form-item>
        </a-col>
      </a-row>
    </a-form>
  </div>
</template>

<script setup lang="ts">
import { computed, reactive, watch } from "vue";
import { IconThunderbolt } from "@arco-design/web-vue/es/icon";

interface FieldItem {
  type: string; // input | textarea | select | number | date
  label: string;
  field: string;
  props?: Record<string, any>;
  options?: Array<{ label: string; value: string | number }>;
  formData?: Record<string, any>;
}

const props = defineProps<{
  schema?: any;
  modelValue?: Record<string, any>;
  // 从 variablePanel.vue 传入的变量列表；可为 {name: string} 或 {label,value}
  variables?: Array<any>;
  // 按分组传入的变量，用于下拉以 Tabs 展示
  variablesGrouped?: {
    process?: Array<{ label: string; value: string }>;
    output?: Array<{ label: string; value: string }>;
    system?: Array<{ label: string; value: string }>;
  };
  // 可选：变量占位符包裹符，默认 {{var}}
  variableWrapper?: { prefix?: string; suffix?: string };
  // 表单配置：对齐 FormPage 的布局
  formConfig?: {
    labelAlign?: "horizontal" | "left" | "right";
    labelWidth?: number;
  };
  // 是否显示变量小按钮（默认不显示，工作流节点属性中可开启）
  showVariableTrigger?: boolean;
}>();
const emit = defineEmits<{
  (e: "update:modelValue", v: Record<string, any>): void;
  (e: "open-variable-panel"): void;
}>();

const model = reactive<Record<string, any>>({});

// 模板使用的变量触发器可见性
const showVariableTrigger = computed(() => !!props.showVariableTrigger);
// 记录变量绑定：当字段被绑定变量时用于控制渲染切换
const varBindings = reactive<Record<string, string | undefined>>({});

// 已不再使用变量包裹符，移除以减少 lints

// 变量列表标准化：优先 label/value，其次 name
const variablesList = computed<{ label: string; value: string }[]>(() => {
  const list = Array.isArray(props.variables) ? props.variables : [];
  return list
    .map((v: any) => ({
      label: String(v.label ?? v.name ?? v.value ?? ""),
      value: String(v.value ?? v.name ?? ""),
    }))
    .filter((v) => v.value);
});

// 分组变量支持：当提供 variablesGrouped 时，使用分组渲染
const hasGrouped = computed(() => {
  const g: any = props.variablesGrouped;
  return !!(g && (g.process?.length || g.output?.length || g.system?.length));
});
const grouped = computed(() => {
  const g: any = props.variablesGrouped || {};
  function norm(arr: any[] | undefined) {
    const list = Array.isArray(arr) ? arr : [];
    return list
      .map((v: any) => ({
        label: String(v.label ?? v.name ?? v.value ?? ""),
        value: String(v.value ?? v.name ?? ""),
      }))
      .filter((v) => v.value);
  }
  return {
    process: norm(g.process),
    output: norm(g.output),
    system: norm(g.system),
  } as {
    process: { label: string; value: string }[];
    output: { label: string; value: string }[];
    system: { label: string; value: string }[];
  };
});

// 将 viewUi 适配为简单字段数组，保留 formData 以支持列宽等配置
const fields = computed<FieldItem[]>(() => {
  const s = props.schema;
  if (!s) return [];
  let parsed: any = s;
  if (typeof s === "string") {
    try {
      parsed = JSON.parse(s);
    } catch {
      return [];
    }
  }
  // 兼容 { pageData, allFormConfig } 结构；或直接是数组
  const pageData = Array.isArray(parsed) ? parsed : parsed.pageData || [];
  const list: FieldItem[] = [];
  for (const it of pageData) {
    const type = it.type || it.component || "input";
    const field = it.field || it.key || it.prop || it.name;
    const label = it.label || it.title || field || "";
    if (!field) continue;
    const item: FieldItem = {
      type: String(type).toLowerCase(),
      field: String(field),
      label: String(label),
      props: it.props || it.componentProps || {},
      options: it.options || it.enum || [],
      formData: it.formData || {},
    };
    list.push(item);
    // 初始值：优先使用外部传入的 modelValue
    const ext = props.modelValue?.[field as string];
    if (ext !== undefined) {
      model[field] = ext;
    } else if (it.defaultValue !== undefined && model[field] === undefined) {
      model[field] = it.defaultValue;
    } else if (model[field] === undefined) {
      model[field] = undefined;
    }
  }
  return list;
});

// 表单布局对齐 FormPage
const formLayout = computed(() =>
  props.formConfig?.labelAlign !== "horizontal" ? "inline" : "horizontal"
);
const labelAlign = computed(() =>
  props.formConfig?.labelAlign === "horizontal"
    ? "left"
    : props.formConfig?.labelAlign || "left"
);
const labelColSpan = computed(() => 4);
const labelColStyle = computed(() => ({
  width: `${props.formConfig?.labelWidth ?? 120}px`,
}));
const wrapperCol = computed(() => ({ span: 24 }));

function colSpan(item: FieldItem) {
  const span = Number(item?.formData?.wrapperCol ?? 24);
  if (!Number.isFinite(span)) return 24;
  return Math.min(Math.max(span, 1), 24);
}

// schema 变化时基于新字段重建内部模型（保持外部值优先）
watch(
  () => props.schema,
  () => {
    const snapshot = { ...(props.modelValue || {}) } as Record<string, any>;
    for (const k of Object.keys(model)) delete (model as any)[k];
    for (const f of fields.value) {
      const key = f.field;
      if (snapshot[key] !== undefined) model[key] = snapshot[key];
      else model[key] = model[key];
    }
    emit("update:modelValue", { ...model });
  }
);

// 外部值变化时，同步到内部
watch(
  () => props.modelValue,
  (nv) => {
    if (!nv) return;
    for (const k of Object.keys(nv)) {
      (model as any)[k] = (nv as any)[k];
    }
  }
);

// 内部模型变化时，透传给上层
watch(
  model,
  () => {
    emit("update:modelValue", { ...model });
  },
  { deep: true }
);

// 保底：当字段被判定为变量绑定且实际渲染为 a-input 时，确保值为字符串以正确回显
watch(
  () => ({
    fields: fields.value.map((f) => ({ field: f.field, type: f.type })),
    m: { ...model },
  }),
  () => {
    for (const item of fields.value) {
      if (isFieldBound(item) && resolveEffectiveComp(item) === "a-input") {
        const field = item.field;
        const v = (model as any)[field];
        if (v !== undefined && v !== null && typeof v !== "string") {
          (model as any)[field] = String(v);
        }
      }
    }
  },
  { deep: true }
);

function resolveComp(item: FieldItem) {
  switch (item.type) {
    case "input":
      return "a-input";
    case "textarea":
      return "a-textarea";
    case "select":
      return "a-select";
    case "number":
    case "inputnumber":
      return "a-input-number";
    case "date":
    case "datepicker":
      return "a-date-picker";
    case "switch":
      return "a-switch";
    default:
      return "a-input";
  }
}

// 若字段已绑定变量，且原始控件不适合字符串，则使用 a-input 回显
function resolveEffectiveComp(item: FieldItem) {
  const base = resolveComp(item);
  const bound = isFieldBound(item);
  if (!bound) return base;
  const nonStringFriendly = ["a-input-number", "a-switch", "a-date-picker"];
  return nonStringFriendly.includes(base) ? "a-input" : base;
}

// 过滤在切换为 a-input 时可能造成冲突/无效的 props，确保变量字符串正常回显
function effectiveProps(item: FieldItem) {
  const raw = (item.props || {}) as Record<string, any>;
  const comp = resolveEffectiveComp(item);
  if (comp !== "a-input") return raw;
  const cleaned: Record<string, any> = { ...raw };
  // 去除 number/switch/datepicker 特有配置
  const removeKeys = [
    "precision",
    "min",
    "max",
    "step",
    "formatter",
    "parser", // input-number
    "checked",
    "defaultChecked",
    "disabled",
    "loading", // switch
    "type",
    "format",
    "valueFormat",
    "showTime",
    "timePickerProps",
    "disabledDate", // date-picker
  ];
  for (const k of removeKeys) delete cleaned[k];
  // 增强 a-input 体验
  if (cleaned.allowClear === undefined) cleaned.allowClear = true;
  return cleaned;
}

// 仅在 a-select 渲染时传入 options，其他组件不需要，避免无意义属性干扰
function effectiveOptions(item: FieldItem) {
  return resolveEffectiveComp(item) === "a-select"
    ? item.options || []
    : undefined;
}

// 判断一个值是否在变量列表里（支持 variables 或 variablesGrouped）
function isValueVariable(v: unknown): boolean {
  if (v === undefined || v === null) return false;
  const s = String(v);
  if (!s) return false;
  // 扁平化所有变量的 value
  const vals: string[] = [];
  for (const it of variablesList.value) vals.push(it.value);
  if (hasGrouped.value) {
    for (const it of grouped.value.process) vals.push(it.value);
    for (const it of grouped.value.output) vals.push(it.value);
    for (const it of grouped.value.system) vals.push(it.value);
  }
  return vals.includes(s);
}

// 字段是否被视为变量绑定：显式绑定或当前值命中变量列表
function isFieldBound(item: FieldItem): boolean {
  const field = item.field;
  if (varBindings[field]) return true;
  const cur = (model as any)[field];
  if (isValueVariable(cur)) return true;
  const base = resolveComp(item);
  const nonStringFriendly = ["a-input-number", "a-switch", "a-date-picker"];
  if (nonStringFriendly.includes(base)) {
    if (typeof cur === "string") {
      const num = Number(cur);
      if (!Number.isFinite(num)) return true; // 非数字字符串，视为变量
    }
  }
  return false;
}

function applyVariable(field: string, name: string) {
  const n = String(name || "").trim();
  if (!n) return;
  // 记录绑定，并以字符串赋值；渲染时由 resolveEffectiveComp 处理组件切换
  varBindings[field] = n;
  (model as any)[field] = n;
}

// 去除变量：清空绑定，并尝试把当前字符串值按原控件类型做友好回退
function clearVariable(item: FieldItem) {
  const field = item.field;
  const cur = (model as any)[field];
  delete varBindings[field];
  const base = resolveComp(item);
  // 仅在存在当前值时尝试回退类型
  if (cur !== undefined && cur !== null && cur !== "") {
    if (base === "a-input-number") {
      const num = Number(cur);
      (model as any)[field] = Number.isFinite(num) ? num : undefined;
      return;
    }
    if (base === "a-switch") {
      const lower = String(cur).toLowerCase();
      if (["true", "1", "yes", "y", "on", "是"].includes(lower)) {
        (model as any)[field] = true;
        return;
      }
      if (["false", "0", "no", "n", "off", "否"].includes(lower)) {
        (model as any)[field] = false;
        return;
      }
      (model as any)[field] = undefined;
      return;
    }
    if (base === "a-date-picker") {
      // 日期无法可靠从字符串恢复，置空让用户重新选择
      (model as any)[field] = undefined;
      return;
    }
    // 其他类型（如 a-input / a-select 等）也清空，确保控件显示的变量文本被移除
    (model as any)[field] = undefined;
    return;
  }
  // 若当前本就为空，也确保为 undefined
  (model as any)[field] = undefined;
}
</script>

<style scoped>
.form-renderer {
  padding-top: 8px;
}
.field-wrap {
  position: relative;
  display: flex;
  align-items: center;
}
.field-control {
  flex: 1 1 auto;
  width: 100%;
}
.var-float-btn {
  position: absolute;
  top: 4px;
  right: 4px;
  z-index: 2;
  padding: 0 4px;
  color: var(--color-primary-6);
}
.var-float-btn:hover {
  color: var(--color-primary-7);
}

/* 对齐 FormPage 的预览风格 */
.draggable_chunk {
  width: 100%;
  padding-bottom: 30px;
}
.column_chunk {
  border: dashed 2px transparent;
  border-radius: 15px;
  position: relative;
}
:deep(.arco-form-item) {
  margin-bottom: 0;
  padding: 10px;
}
:deep(.arco-form-item-content) {
  height: 100% !important;
}
</style>
